package com.hy.service;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.protobuf.ServiceException;
import com.hy.mapper.SensitiveWordMapper;
import com.hy.medicine.evaluation.pojo.SensitiveWord;
import com.hy.until.CheckResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import springfox.documentation.annotations.Cacheable;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 敏感词服务实现
 */
@Service
@Slf4j
public class SensitiveWordServiceImpl extends ServiceImpl<SensitiveWordMapper, SensitiveWord> implements SensitiveWordService {

    @Autowired
    private SensitiveWordMapper sensitiveWordMapper;

    private Map<String, Integer> wordMap; // 敏感词Map
    private DFANode rootNode; // DFA树根节点

    /**
     * 初始化敏感词库和DFA树
     */
    @PostConstruct
    public void init() {
        // 初始化敏感词库
        loadSensitiveWords();
        // 构建DFA树
        buildDFATree();
    }

    /**
     * 过滤内容，替换敏感词
     * @param content 待过滤内容
     * @return
     * @throws ServiceException
     */
    @Override
    public String filter(String content) throws ServiceException {
        if (StringUtils.isBlank(content)) {
            return content;
        }

        CheckResult checkResult = check(content);
        if (!checkResult.isContainsSensitiveWord()) {
            return content;
        }

        // 根据级别处理
        if (checkResult.getMaxLevel() >= 3) {
            throw new ServiceException("内容包含违禁词，请修改");
        }

        // 替换敏感词
        String filtered = content;
        for (String word : checkResult.getWords()) {
            filtered = filtered.replaceAll(word, String.join("", Collections.nCopies(word.length(), "*")));
        }
        return filtered;
    }

    /**
     * 检查内容，返回敏感词级别和敏感词列表
     * @param content 待检查内容
     * @return
     */
    @Override
    public CheckResult check(String content) {
        CheckResult result = new CheckResult();
        result.setContainsSensitiveWord(false);
        result.setWords(new ArrayList<>());
        result.setMaxLevel(0);

        if (StringUtils.isBlank(content)) {
            return result;
        }

        char[] chars = content.toCharArray();
        int length = chars.length;
        int currentIndex = 0;

        while (currentIndex < length) {
            int level = checkWord(chars, currentIndex);
            if (level > 0) {
                String word = findWord(chars, currentIndex);
                result.setContainsSensitiveWord(true);
                result.getWords().add(word);
                result.setMaxLevel(Math.max(result.getMaxLevel(), level));
                currentIndex += word.length();
            } else {
                currentIndex++;
            }
        }

        return result;
    }

    /**
     * 添加敏感词
     * @param word 敏感词
     * @param level 级别
     * @throws ServiceException
     */
    @Override
    @CacheEvict(value = "sensitiveWords", allEntries = true)
    public void addWord(String word, Integer level) throws ServiceException {
        // 验证参数
        if (StringUtils.isBlank(word) || level == null) {
            throw new ServiceException("参数错误");
        }

        // 检查是否已存在
        if (wordMap.containsKey(word)) {
            throw new ServiceException("敏感词已存在");
        }

        // 保存敏感词
        SensitiveWord sensitiveWord = new SensitiveWord();
        sensitiveWord.setWord(word);
        sensitiveWord.setLevel(level);
        sensitiveWordMapper.insert(sensitiveWord);

        // 更新缓存
        wordMap.put(word, level);
        // 更新DFA树
        updateDFANode(word, level);
    }

    /**
     * 更新DFA树节点
     */
    private void updateDFANode(String word, Integer level) {
        if (StringUtils.isBlank(word)) {
            return;
        }

        DFANode currentNode = rootNode;
        char[] chars = word.toCharArray();

        // 遍历字符构建DFA树
        for (char c : chars) {
            // 如果当前字符的节点不存在，则创建新节点
            currentNode.children.putIfAbsent(c, new DFANode());
            // 移动到下一个节点
            currentNode = currentNode.children.get(c);
        }

        // 设置结束标记和敏感词级别
        currentNode.isEnd = true;
        currentNode.level = level;
    }

    /**
     * 删除敏感词
     * @param wordId 敏感词ID
     */
    @Override
    @CacheEvict(value = "sensitiveWords", allEntries = true)
    public void deleteWord(Integer wordId) {
        SensitiveWord word = sensitiveWordMapper.selectById(wordId);
        if (word != null) {
            sensitiveWordMapper.deleteById(wordId);
            wordMap.remove(word.getWord());
            // 重建DFA树
            buildDFATree();
        }
    }

    /**
     * 加载敏感词库
     */
    @Cacheable(value = "sensitiveWords")
    private void loadSensitiveWords() {
        List<SensitiveWord> words = sensitiveWordMapper.selectAllWords();
        wordMap = words.stream().collect(
            Collectors.toMap(SensitiveWord::getWord, SensitiveWord::getLevel)
        );
    }

    /**
     * 构建DFA树
     */
    private void buildDFATree() {
        rootNode = new DFANode();
        for (Map.Entry<String, Integer> entry : wordMap.entrySet()) {
            String word = entry.getKey();
            Integer level = entry.getValue();
            addWordToDFA(word, level);
        }
    }

    /**
     * 将单个词添加到DFA树
     */
    private void addWordToDFA(String word, Integer level) {
        DFANode currentNode = rootNode;
        for (char c : word.toCharArray()) {
            currentNode.children.putIfAbsent(c, new DFANode());
            currentNode = currentNode.children.get(c);
        }
        currentNode.isEnd = true;
        currentNode.level = level;
    }

    /**
     * 检查从指定位置开始的敏感词级别
     */
    private int checkWord(char[] chars, int begin) {
        DFANode currentNode = rootNode;
        int level = 0;
        int position = begin;

        while (position < chars.length) {
            char c = chars[position];
            DFANode node = currentNode.children.get(c);
            if (node == null) {
                break;
            }
            if (node.isEnd) {
                level = Math.max(level, node.level);
            }
            currentNode = node;
            position++;
        }

        return level;
    }

    /**
     * 查找完整的敏感词
     */
    private String findWord(char[] chars, int begin) {
        StringBuilder word = new StringBuilder();
        DFANode currentNode = rootNode;
        int position = begin;

        while (position < chars.length) {
            char c = chars[position];
            DFANode node = currentNode.children.get(c);
            if (node == null) {
                break;
            }
            word.append(c);
            if (node.isEnd) {
                break;
            }
            currentNode = node;
            position++;
        }

        return word.toString();
    }

    /**
     * DFA节点类
     */
    private static class DFANode {
        Map<Character, DFANode> children = new HashMap<>();
        boolean isEnd;
        int level;
    }
}
